/*
 *  Copyright (C) 2008      Tri Tech Information Systems Inc.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <QString>
#include <QStringList>

#include "pyQList.h"

#include <boost/python.hpp>
using namespace boost::python;

struct QString_to_Unicode
{
    static PyObject* convert( const QString& s )
    {
        if( s.isNull() )
            Py_RETURN_NONE;
        else
        {
            // TODO: There's an extra copy here, get rid of it somehow...
            std::wstring ws = s.toStdWString();
            return PyUnicode_FromWideChar( ws.c_str(), ws.size() );
        }
    }

    static PyTypeObject const* get_pytype()
    {  
        return &PyUnicode_Type;
    }
};

struct toQString
{
    static void* convertible( PyObject* obj )
    {
        if( !PyString_Check(obj) && !PyUnicode_Check(obj) ) 
            return 0;

        return obj;
    }

    static void construct( PyObject* obj, converter::rvalue_from_python_stage1_data* data )
    {
        typedef converter::rvalue_from_python_storage<QString> storage_t;
        storage_t* the_storage = reinterpret_cast<storage_t*>( data );
        void* memory_chunk = the_storage->storage.bytes;

        QString* s;
        if( PyString_Check(obj) )
            s = new (memory_chunk) QString( PyString_AS_STRING(obj) );
        else
        {
            // TODO: Extra copy here, too  =(
            Py_ssize_t sz = PyUnicode_GetSize(obj);
            wchar_t* ws = new wchar_t[sz];
            PyUnicode_AsWideChar( (PyUnicodeObject*)obj, ws, sz );

            s = new (memory_chunk) QString( QString::fromWCharArray( ws, sz ) );
            delete ws;
        }
        data->convertible = memory_chunk;
    }
};

struct toQStringList
{
    static void* convertible( PyObject* obj )
    {
        if( !PyList_Check(obj) )
            return 0;

        for( Py_ssize_t i = 0, len = PyList_GET_SIZE(obj); i < len; ++i )
        {
            PyObject* item = PyList_GET_ITEM( obj, i );
            if( !PyString_Check(item) && !PyUnicode_Check(item) )
                return 0;
        }


        return obj;
    }

    static void construct( PyObject* obj, converter::rvalue_from_python_stage1_data* data )
    {
        typedef converter::rvalue_from_python_storage<QStringList> storage_t;
        storage_t* the_storage = reinterpret_cast<storage_t*>( data );
        void* memory_chunk = the_storage->storage.bytes;

        QStringList* sl = new (memory_chunk) QStringList();
        for( Py_ssize_t i = 0, len = PyList_GET_SIZE(obj); i < len; ++i )
            sl->append( extract<QString>(PyList_GET_ITEM(obj, i)) );

        data->convertible = memory_chunk;
    }
};

std::auto_ptr<QStringList> QStringList_fromPyList( list lst )
{
    std::auto_ptr<QStringList> sl( new QStringList() );
    for( Py_ssize_t i = 0, len = PyList_GET_SIZE(lst.ptr()); i < len; ++i )
        *sl << extract<QString>(lst[i]);

    return sl;
}


void Wrap_QtCore()
{
    to_python_converter< QString, QString_to_Unicode >();
    converter::registry::push_back( &toQString::convertible,
            &toQString::construct, type_id<QString>() );


    Wrap_QList< QString >();

    class_< QStringList, bases<QList<QString> > >( "QStringList" )
        .def( "__init__", make_constructor(QStringList_fromPyList) )
        ;

    converter::registry::push_back( &toQStringList::convertible,
            &toQStringList::construct, type_id<QStringList>() );
}



